home *** CD-ROM | disk | FTP | other *** search
/ Delphi Informant Complete 1995 - 2000 / Delphi Informant Complete 1995 to 2000.iso / Delphi Informant Magazine Complete Works SOURCE CODE 1998.rar / 1998 / Jul / di9807rl / gradient.pas < prev    next >
Pascal/Delphi Source File  |  1998-02-24  |  8KB  |  283 lines

  1. unit Gradient;
  2.  
  3. { Demostration of palettes in a Delphi component.
  4.   Copyright ⌐ 1998 Tempest Software, Inc.
  5.  
  6.   The TGradient component displays a color gradient, with
  7.   a user-specified starting and ending color, and number of
  8.   color steps between them.
  9. }
  10.  
  11. interface
  12.  
  13. uses
  14.   SysUtils, Windows, Messages, Classes, Graphics, Controls, ExtCtrls;
  15.  
  16. type
  17.   TGradientOrientation = (goVertical, goHorizontal);
  18.   TNumColors = 1..255;
  19.   TGradient = class(TGraphicControl)
  20.   private
  21.     // Colors for the end pointers in the gradient
  22.     fColorTop, fColorBottom: TColor;
  23.     // Number of steps in the gradient
  24.     fNumColors: TNumColors;
  25.     // Horizontal or vertical gradient
  26.     fOrientation: TGradientOrientation;
  27.  
  28.     // Palette information
  29.     fPalette: HPalette;           // handle to the palette
  30.     fLogPalette: PLogPalette;     // pointer to logical palette
  31.  
  32.     procedure SetColorTop(Value: TColor);
  33.     procedure SetColorBottom(Value: TColor);
  34.     procedure SetNumColors(Value: TNumColors);
  35.     procedure SetOrientation(Value: TGradientOrientation);
  36.     procedure WmEraseBkgnd(var Msg: TWmEraseBkgnd); message Wm_EraseBkgnd;
  37.   protected
  38.     procedure AllocatePalette(NumColors: Integer); virtual;
  39.     procedure DestroyPalette; virtual;
  40.     procedure GetColor(var Red, Green, Blue: Byte; Index: Integer); virtual;
  41.     function GetPalette: HPalette; override;
  42.     function MakePalette: HPalette; virtual;
  43.     procedure Paint; override;
  44.     property Palette: HPalette read fPalette;
  45.     property LogPalette: PLogPalette read fLogPalette;
  46.   public
  47.     constructor Create(Owner: TComponent); override;
  48.     destructor Destroy; override;
  49.   published
  50.     property Align;
  51.     property DragCursor;
  52.     property DragMode;
  53.     property Height default 100;
  54.     property Visible;
  55.     property Width default 100;
  56.     property OnDblClick;
  57.     property OnDragOver;
  58.     property OnDragDrop;
  59.     property OnEndDrag;
  60.     property OnMouseMove;
  61.     property OnMouseDown;
  62.     property OnMouseUp;
  63.     property OnClick;
  64.     property OnStartDrag;
  65.     property ColorTop: TColor read fColorTop write SetColorTop default clBlue;
  66.     property ColorBottom: TColor read fColorBottom write SetColorBottom default clBlack;
  67.     property NumColors: TNumColors read fNumColors write SetNumColors default 64;
  68.     property Orientation: TGradientOrientation read fOrientation write SetOrientation;
  69.   end;
  70.  
  71. procedure Register;
  72.  
  73. implementation
  74.  
  75. // Create and initialize the control. Start with 64 steps
  76. // because most palette devices use 18 bits per pixel,
  77. // which means 6 bits per color, or 64 distinct colors.
  78. // The colors blue and black look nice, but feel free to
  79. // change them to whatever you find more aesthetic.
  80. // Ditto for the default size.
  81. constructor TGradient.Create(Owner: TComponent);
  82. begin
  83.   inherited Create(Owner);
  84.  
  85.   fColorTop := clBlue;
  86.   fColorBottom := clBlack;
  87.   fNumColors := 64;
  88.  
  89.   Height := 100;
  90.   Width := 100;
  91. end;
  92.  
  93. // Destroy the control.
  94. // Clean up by freeing the palette resource and memory.
  95. destructor TGradient.Destroy;
  96. begin
  97.   DestroyPalette;
  98.   inherited Destroy;
  99. end;
  100.  
  101. // Calculate a color at position Index in the gradient, and set
  102. // the Red, Green, and Blue arguments to the color's elements.
  103. procedure TGradient.GetColor(var Red, Green, Blue: Byte; Index: Integer);
  104. var
  105.   Top, Bottom: TColor;
  106.   NumColors: Integer;
  107. begin
  108.   Top := ColorToRgb(ColorTop);
  109.   Bottom := ColorToRgb(ColorBottom);
  110.   NumColors := LogPalette.palNumEntries;
  111.  
  112.   Red :=
  113.     MulDiv(NumColors-Index-1, GetRValue(Top), NumColors-1) +
  114.     MulDiv(Index, GetRValue(Bottom), NumColors-1);
  115.  
  116.   Green :=
  117.     MulDiv(NumColors-Index-1, GetGValue(Top), NumColors-1) +
  118.     MulDiv(Index, GetGValue(Bottom), NumColors-1);
  119.  
  120.   Blue :=
  121.     MulDiv(NumColors-Index-1, GetBValue(Top), NumColors-1) +
  122.     MulDiv(Index, GetBValue(Bottom), NumColors-1);
  123. end;
  124.  
  125. // Allocate the logical palette record so it is large enough
  126. // for NumColors palette entries. The caller must already have
  127. // destroyed the old palette. After calling AllocatePalette,
  128. // the caller must initialize the palette entries.
  129. procedure TGradient.AllocatePalette(NumColors: Integer);
  130. begin
  131.   Assert(LogPalette = nil);
  132.  
  133.   // TLogPalette already has one palette entry, so we need NumColors-1 more.
  134.   GetMem(fLogPalette, SizeOf(TLogPalette) + (NumColors-1)*SizeOf(TPaletteEntry));
  135.   LogPalette.palVersion := $300;
  136.   LogPalette.palNumEntries := NumColors;
  137. end;
  138.  
  139. // Make a gradient palette and return the palette handle.
  140. // Call this once when initializing the control.
  141. // If the user changes the number of steps or the colors,
  142. // recreate the palette with the new information.
  143. function TGradient.MakePalette: HPalette;
  144. var
  145.   I: Integer;
  146. begin
  147.   AllocatePalette(NumColors);
  148.  
  149.   {$R- Turn off range checking to access palette entries.}
  150.   for I := 0 to LogPalette.palNumEntries-1 do
  151.     with LogPalette.palPalEntry[I] do
  152.     begin
  153.       GetColor(peRed, peGreen, peBlue, I);
  154.       peFlags := 0
  155.     end;
  156.   {$R+}
  157.  
  158.   Result := CreatePalette(LogPalette^);
  159. end;
  160.  
  161. // Destroy the palette and free the palette memory.
  162. procedure TGradient.DestroyPalette;
  163. begin
  164.   if Palette <> 0 then
  165.   begin
  166.     DeleteObject(Palette);
  167.     fPalette := 0;
  168.   end;
  169.   FreeMem(LogPalette);
  170.   fLogPalette := nil;
  171. end;
  172.  
  173. // Change the top color.
  174. procedure TGradient.SetColorTop(Value: TColor);
  175. begin
  176.   if Value <> ColorTop then
  177.   begin
  178.     fColorTop := Value;
  179.     DestroyPalette;
  180.     Invalidate;
  181.   end;
  182. end;
  183.  
  184. // Change the bottom color.
  185. procedure TGradient.SetColorBottom(Value: TColor);
  186. begin
  187.   if Value <> ColorBottom then
  188.   begin
  189.     fColorBottom := Value;
  190.     DestroyPalette;
  191.     Invalidate;
  192.   end;
  193. end;
  194.  
  195. // Change the direction of the gradient.
  196. procedure TGradient.SetOrientation(Value: TGradientOrientation);
  197. begin
  198.   if Value <> Orientation then
  199.   begin
  200.     fOrientation := Value;
  201.     Invalidate;
  202.   end;
  203. end;
  204.  
  205. // Change the number of steps in the gradient. Note that
  206. // this requires rebuilding the palette with a new size.
  207. procedure TGradient.SetNumColors(Value: TNumColors);
  208. begin
  209.   if Value <> NumColors then
  210.   begin
  211.     fNumColors := Value;
  212.     DestroyPalette;
  213.     Invalidate;
  214.   end;
  215. end;
  216.  
  217. // Return the palette handle, building the palette if necessary.
  218. function TGradient.GetPalette: HPalette;
  219. begin
  220.   if Palette = 0 then
  221.     fPalette := MakePalette;
  222.   Result := Palette;
  223. end;
  224.  
  225. // Paint the gradient. Tell Windows to use the palette when
  226. // painting this control. To do this, explicitly select
  227. // the palette and use PaletteIndex as the color.
  228. //
  229. // To paint the gradient, divide the canvas into NumColors bands,
  230. // and fill each band with a solid color, chosen from the palette.
  231. procedure TGradient.Paint;
  232. var
  233.   I: Integer;
  234.   X, Y: Integer;       // current position on canvas
  235.   Rect: TRect;         // rectangle for filling one band in the gradient
  236.   OldPal: HPalette;    // old palette
  237.   Red, Green, Blue: Byte;
  238. begin
  239.   Rect := ClientRect;
  240.   Y := 0;
  241.   X := 0;
  242.   OldPal := SelectPalette(Canvas.Handle, GetPalette, False);
  243.   try
  244.     for I := 0 to NumColors-1 do
  245.     begin
  246.       {$R-}
  247.       with LogPalette.palPalEntry[I] do
  248.         Canvas.Brush.Color := PaletteRgb(peRed, peGreen, peBlue);
  249.       {$R+}
  250.       if Orientation = goVertical then
  251.       begin
  252.         Rect.Top := Y;
  253.         Y := MulDiv(ClientHeight, I + 1, NumColors);
  254.         Rect.Bottom := Y;
  255.       end
  256.       else
  257.       begin
  258.         Rect.Left := X;
  259.         X := MulDiv(ClientWidth, I + 1, NumColors);
  260.         Rect.Right := X;
  261.       end;
  262.       Canvas.FillRect(Rect);
  263.     end;
  264.   finally
  265.     SelectPalette(Canvas.Handle, OldPal, False);
  266.   end;
  267. end;
  268.  
  269. // Do not erase the background because the Paint method repaints
  270. // the entire client area. This reduces flicker.
  271. procedure TGradient.WmEraseBkgnd(var Msg: TWmEraseBkgnd);
  272. begin
  273.   Msg.Result := 1;
  274. end;
  275.  
  276.  
  277. procedure Register;
  278. begin
  279.   RegisterComponents('Tempest', [TGradient]);
  280. end;
  281.  
  282. end.
  283.